//! 请求指令

use crate::send;
use alloc::vec::Vec;
use fixed_queue::LinearMap;
use futures_intrusive::buffer::ArrayBuf;
use futures_intrusive::channel::shared::*;
use futures_intrusive::sync::GenericMutex;
use spin::Lazy;
use spin::Mutex;
use unmp::id::Id;
use unmp_center_core::{get_code, Cmd, Data, Kind, Status};

type AsyncMutex<T> = GenericMutex<Mutex<()>, T>;
type RingBody = ArrayBuf<Data, [Data; 1]>;
type WaitDataSender = GenericSender<Mutex<()>, Data, RingBody>;
static WAIT_LIST: Lazy<AsyncMutex<LinearMap<u16, WaitDataSender, 4>>> =
    Lazy::new(|| AsyncMutex::new(LinearMap::new(), false));

/// 接收响应数据
pub(crate) async fn recv(data: Data) {
    let wait_list = WAIT_LIST.lock().await;
    if let Some(sender) = wait_list.get(&data.sn()) {
        let _err = sender.send(data).await;
    }
}

pub async fn get_id(product_id: u64, product_key: &[u8; 8]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::GetId, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, &product_id.to_be_bytes(), product_key);
    let cmd = Cmd::GetIdReq {
        product_id: product_id,
        product_code: code,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn login(id: &Id, private_key: &[u8; 8]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::Login, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, private_key);
    let cmd = Cmd::LoginReq { code: code };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn heart() -> Result<Data, ()> {
    let mut data = Data::new(Kind::Heart, Status::Request);
    let sn = data.sn();
    let cmd = Cmd::HeartReq {};
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn get_timestamp() -> Result<Data, ()> {
    let mut data = Data::new(Kind::GetTimestamp, Status::Request);
    let sn = data.sn();
    let cmd = Cmd::GetTimestampReq {};
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}

pub async fn set_actual(id: &Id, public_key: &[u8; 8], k: u16, v: &[u8]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::SetActual, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::SetActualReq {
        id: id.clone(),
        code: code,
        k: k,
        v: Vec::from(v),
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn get_actual(id: &Id, public_key: &[u8; 8], k: u16) -> Result<Data, ()> {
    let mut data = Data::new(Kind::GetActual, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::GetActualReq {
        id: id.clone(),
        code: code,
        k: k,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn sub_actual(id: &Id, public_key: &[u8; 8], k: u16) -> Result<Data, ()> {
    let mut data = Data::new(Kind::SubActual, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::SubActualReq {
        id: id.clone(),
        code: code,
        k: k,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn sub_all_actual(id: &Id, public_key: &[u8; 8]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::SubAllActual, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::SubAllActualReq {
        id: id.clone(),
        code: code,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn notice_actual(id: &Id, k: u16, v: &[u8]) -> Result<(), ()> {
    let mut data = Data::new(Kind::NoticeActual, Status::Notice);
    let cmd = Cmd::NoticeActual {
        id: id.clone(),
        k: k,
        v: Vec::from(v),
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    return Ok(());
}

pub async fn set_target(id: &Id, public_key: &[u8; 8], k: u16, v: &[u8]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::SetTarget, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::SetTargetReq {
        id: id.clone(),
        code: code,
        k: k,
        v: Vec::from(v),
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn get_target(id: &Id, public_key: &[u8; 8], k: u16) -> Result<Data, ()> {
    let mut data = Data::new(Kind::GetTarget, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::GetTargetReq {
        id: id.clone(),
        code: code,
        k: k,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn sub_target(id: &Id, public_key: &[u8; 8], k: u16) -> Result<Data, ()> {
    let mut data = Data::new(Kind::SubTarget, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::SubTargetReq {
        id: id.clone(),
        code: code,
        k: k,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn sub_all_target(id: &Id, public_key: &[u8; 8]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::SubAllTarget, Status::Request);
    let sn = data.sn();
    let code = get_code(sn, id, public_key);
    let cmd = Cmd::SubAllTargetReq {
        id: id.clone(),
        code: code,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn notice_target(id: &Id, k: u16, v: &[u8]) -> Result<(), ()> {
    let mut data = Data::new(Kind::NoticeTarget, Status::Notice);
    let cmd = Cmd::NoticeTarget {
        id: id.clone(),
        k: k,
        v: Vec::from(v),
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    return Ok(());
}
pub async fn enter_bind(code: [u8; 4]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::EnterBind, Status::Request);
    let sn = data.sn();
    let cmd = Cmd::EnterBindReq { code: code };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn bind(product_id: u64, code: [u8; 4]) -> Result<Data, ()> {
    let mut data = Data::new(Kind::Bind, Status::Request);
    let sn = data.sn();
    let cmd = Cmd::BindReq {
        product_id,
        code: code,
    };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
pub async fn unbind(id: &Id) -> Result<Data, ()> {
    let mut data = Data::new(Kind::Unbind, Status::Request);
    let sn = data.sn();
    let cmd = Cmd::UnbindReq { id: id.clone() };
    data.set_cmd(cmd);
    send(&data.to_buf()).await?;
    let (sender, recver) = generic_channel(1);
    WAIT_LIST.lock().await.insert(sn, sender);
    if let Some(res) = recver.receive().await {
        return Ok(res);
    } else {
        return Err(());
    }
}
